let marbleRaceUIEngine = {
	setColor: function (element, color, isText = false) {
		let colorCalculated = marbleRaceColorUtility.calculateColor(color)

		if (isText) {
			element.style.color = colorCalculated.stroke
		} else {
			element.style.borderWidth = colorCalculated.lineWidth
			element.style.borderStyle = 'solid'
			element.style.borderColor = colorCalculated.stroke
			if (colorCalculated.sprite) {
				element.style.backgroundColor = undefined
				element.style.backgroundImage = 'url(' + colorCalculated.sprite + ')'
				element.style.backgroundSize = 'cover'
			} else {
				element.style.backgroundColor = colorCalculated.fill
				element.style.backgroundImage = undefined
				element.style.backgroundSize = undefined
			}
		}
	},
	update: function () {
		let showValue = this.status.showValue
		let levelTime = this.time
		let totalTime = this.totalTime
		marbleRaceConfig.levelTimeElement.innerText = levelTime.toFixed(2)
		marbleRaceConfig.totalTimeElement.innerText = totalTime.toFixed(2)
		for (let i = 0; i < this.n; ++i) {
			let si = this.status[i]
			let text = 'UNKNOWN'
			switch (si.status) {
				case marbleRaceConfig.constant.UNKNOWN:
					text = marbleRaceConfig.text.statusUnknown
					break
				case marbleRaceConfig.constant.UNFINISHED:
					if (showValue)
						text = marbleRaceConfig.text.statusUnfinishedValue
					else
						text = marbleRaceConfig.text.statusUnfinished
					break
				case marbleRaceConfig.constant.PASSED:
					if (showValue)
						text = marbleRaceConfig.text.statusPassedValue
					else
						text = marbleRaceConfig.text.statusPassed
					break
				case marbleRaceConfig.constant.ELIMINATED:
					text = marbleRaceConfig.text.statusEliminated
					break
				case marbleRaceConfig.constant.PROMOTED:
					text = marbleRaceConfig.text.statusPromoted
					break
				case marbleRaceConfig.constant.WIN:
					text = marbleRaceConfig.text.statusWin
					break
				default:
					text = marbleRaceConfig.text.statusUnknown
			}
			if (si.score !== undefined)
				text = text.replace('%s', si.score)
			if (si.passTime !== undefined)
				text = text.replace('%t', si.passTime.toFixed(2))
			if (si.value !== undefined)
				text = text.replace('%v', si.value.toFixed(2))
			this.colorStatusTags[i].innerHTML = text
		}

		if (marbleRaceConfig.theme.displayStatus) {
			for (let i = 0; i < this.m; ++i)
				this.setColor(this.teamTags[i], this.colors[this.captains[i]].color, true)
			for (let i = 0; i < this.n; ++i)
				this.setColor(this.colorTags[i], this.colors[i].color, true)
			if (marbleRaceConfig.theme.displayBallTag)
				for (let i = 0; i < this.n; ++i)
					this.setColor(this.colorBallTags[i], this.colors[i].color, false)
		}
		if (marbleRaceConfig.theme.displayRanklist) {
			for (let i = 0; i < this.n; ++i) {
				let rank = this.status[i].rank
				if (rank !== undefined) {
					let team = this.colors[i].team
					this.rankTeamElements[rank].innerHTML = this.teams[team].name
					this.rankColorElements[rank].innerHTML = this.colors[i].name
					this.rankScoreElements[rank].innerHTML = marbleRaceConfig.text.score.replace('%s', this.status[i].score.toString())
					this.setColor(this.rankTeamElements[rank], this.colors[this.captains[team]].color, true)
					this.setColor(this.rankColorElements[rank], this.colors[i].color, true)
				}
			}
			if (this.temporaryRanklistKey) {
				let temporaryRanklist = new Array();
				for (let i = 0; i < this.n; ++i) {
					if (this.status[i].rank === undefined) {
						temporaryRanklist.push({
							value: this.status[i][this.temporaryRanklistKey],
							id: i
						})
					}
				}
				temporaryRanklist.sort(function (a, b) {
					if (a.value > b.value)
						return -1
					if (a.value < b.value)
						return 1
					return a.id - b.id
				})
				function setTemporaryStyle(element) {
					element.style.fontWeight = '100'
					element.style.fontStyle = 'italic'
				}
				function setNonTemporaryStyle(element) {
					element.style.fontWeight = '900'
					element.style.fontStyle = 'normal'
				}
				let len = temporaryRanklist.length
				for (let rank = 0; rank < len; ++rank) {
					let i = temporaryRanklist[rank].id
					let v = temporaryRanklist[rank].value
					let team = this.colors[i].team
					this.rankTeamElements[rank].innerHTML = this.teams[team].name
					this.rankColorElements[rank].innerHTML = this.colors[i].name
					this.rankScoreElements[rank].innerHTML = marbleRaceConfig.text.scoreTemporary.replace('%s', v.toFixed(2))
					this.setColor(this.rankTeamElements[rank], this.colors[this.captains[team]].color, true)
					this.setColor(this.rankColorElements[rank], this.colors[i].color, true)

					setTemporaryStyle(this.rankTags[rank])
					setTemporaryStyle(this.rankTeamElements[rank])
					setTemporaryStyle(this.rankColorElements[rank])
					setTemporaryStyle(this.rankScoreElements[rank])
				}
				for (let rank = len; rank < n; ++rank) {
					setNonTemporaryStyle(this.rankTags[rank])
					setNonTemporaryStyle(this.rankTeamElements[rank])
					setNonTemporaryStyle(this.rankColorElements[rank])
					setNonTemporaryStyle(this.rankScoreElements[rank])
				}
			}
		}
		if (marbleRaceConfig.statusMessageElement) {
			let text
			switch (this.status.lastStatus) {
				case marbleRaceConfig.constant.PASSED:
					if (this.setting.hidePassedMessage)
						text = undefined
					else
						text = marbleRaceConfig.statusMessage.passed
					break
				case marbleRaceConfig.constant.UNFINISHED:
					text = marbleRaceConfig.statusMessage.unpassed
					break
				case marbleRaceConfig.constant.ELIMINATED:
					text = marbleRaceConfig.statusMessage.eliminated
					break
				case marbleRaceConfig.constant.PROMOTED:
					if (this.setting.hidePromotedMessage)
						text = undefined
					else
						text = marbleRaceConfig.statusMessage.promoted
					break
				case marbleRaceConfig.constant.WIN:
					text = marbleRaceConfig.statusMessage.win
					break
				case marbleRaceConfig.constant.SACRIFICED:
					text = marbleRaceConfig.statusMessage.sacrificed
					break
				default:
					text = undefined
			}
			if (text) {
				let statusMessageElement = marbleRaceConfig.statusMessageElement
				statusMessageElement.innerHTML = ''

				let marbleID = this.status.lastStatusMarble
				let lastStatusMarbleTag = document.createElement('span')
				//lastStatusMarbleTag.style.margin = '0'
				lastStatusMarbleTag.innerText = this.colors[marbleID].name

				statusMessageElement.appendChild(lastStatusMarbleTag)

				this.setColor(lastStatusMarbleTag, this.colors[marbleID].color, true)

				let lastStatusTextTag = document.createElement('span')
				//lastStatusTextTag.style.margin = '0'
				lastStatusTextTag.innerHTML = text

				statusMessageElement.appendChild(lastStatusTextTag)
			}
		}
	},
	init: function (title, config, status, setting = {}) {
		this.colors = config.colors
		this.teams = config.teams
		this.status = status
		this.setting = setting

		this.time = 0
		if (!this.totalTime)
			this.totalTime = 0

		this.n = this.colors.length
		this.m = this.teams.length

		this.teamMembers = new Array(this.m)
		this.captains = new Array(this.m)

		if (marbleRaceConfig.theme.displayStatus) {
			this.teamTags = new Array(this.m)
			this.colorTags = new Array(this.n)
			this.colorStatusTags = new Array(this.n)
			if (marbleRaceConfig.theme.displayBallTag)
				this.colorBallTags = new Array(this.n)
		}
		if (marbleRaceConfig.theme.displayRanklist) {
			this.rankTags = new Array(this.n)
			this.rankTeamElements = new Array(this.n)
			this.rankColorElements = new Array(this.n)
			this.rankScoreElements = new Array(this.n)
		}

		for (let i = 0; i < this.m; ++i)
			this.teamMembers[i] = []
		for (let i = 0; i < this.n; ++i) {
			let color = this.colors[i]
			this.teamMembers[color.team].push(i)
			if (color.isCaptain)
				this.captains[color.team] = i
		}

		marbleRaceConfig.leftPanel.innerHTML = ''
		marbleRaceConfig.rightPanel.innerHTML = ''
		{
			let levelTextTag = document.createElement('b')
			levelTextTag.style.fontSize = '24px'
			levelTextTag.innerHTML = title
			marbleRaceConfig.leftPanel.appendChild(levelTextTag)
		}
		{
			let levelTextTag = document.createElement('b')
			levelTextTag.style.fontSize = '24px'
			if (setting.comment)
				levelTextTag.innerHTML = setting.comment
			else
				levelTextTag.innerHTML = title
			marbleRaceConfig.rightPanel.appendChild(levelTextTag)
		}

		if (marbleRaceConfig.theme.displayStatus)
			for (let teamID = 0; teamID < this.m; ++teamID) {
				let panel = (teamID + teamID < this.m) ? (marbleRaceConfig.leftPanel) : (marbleRaceConfig.rightPanel)

				let teamElement = document.createElement('div')
				teamElement.style.display = 'flex'
				teamElement.style.flexDirection = 'column'
				teamElement.style.alignItems = 'center'
				teamElement.style.width = '100%'

				let teamTag = document.createElement('b')
				teamTag.innerText = this.teams[teamID].name

				teamElement.appendChild(teamTag)
				this.teamTags[teamID] = teamTag

				let teamMemberElement = document.createElement('div')
				teamMemberElement.style.display = 'flex'
				teamMemberElement.style.flexWrap = 'wrap'
				teamMemberElement.style.flexDirection = 'row'
				teamMemberElement.style.justifyContent = 'center'
				teamMemberElement.style.width = '100%'

				for (let i = 0; i < this.teamMembers[teamID].length; ++i) {
					let colorID = this.teamMembers[teamID][i]
					let colorElement = document.createElement('div')
					colorElement.style.width = '20%'
					colorElement.style.display = 'flex'
					colorElement.style.flexDirection = 'column'
					colorElement.style.alignItems = 'center'

					let colorTag = document.createElement('p')
					colorTag.style.margin = '0'
					colorTag.innerText = this.colors[colorID].name

					colorElement.appendChild(colorTag)
					this.colorTags[colorID] = colorTag

					if (marbleRaceConfig.theme.displayBallTag) {
						let colorBallTag = document.createElement('div')
						colorBallTag.style.margin = '0'
						colorBallTag.style.width = (marbleRaceConfig.theme.ballRadius * 2) + 'px'
						colorBallTag.style.height = (marbleRaceConfig.theme.ballRadius * 2) + 'px'
						colorBallTag.style.borderRadius = '50%'

						colorElement.appendChild(colorBallTag)
						this.colorBallTags[colorID] = colorBallTag
					}

					let colorStatusTag = document.createElement('p')
					colorStatusTag.style.margin = '0'

					this.colorStatusTags[colorID] = colorStatusTag

					colorElement.appendChild(colorStatusTag)

					teamMemberElement.appendChild(colorElement)
				}

				teamElement.appendChild(teamMemberElement)

				panel.appendChild(teamElement)
			}

		if (marbleRaceConfig.theme.displayRanklist) {
			let digits = Math.floor(Math.log10(this.n)) + 1
			for (let i = 1; i <= this.n; ++i) {
				let iStr = ''
				let iTmp = i
				for (let j = 0; j < digits; ++j) {
					iStr = '0123456789'[iTmp % 10] + iStr
					iTmp = Math.floor(.1 * iTmp)
				}
				let panel = (i + i <= this.n) ? (marbleRaceConfig.leftPanel) : (marbleRaceConfig.rightPanel)

				let rankElement = document.createElement('div')
				rankElement.style.width = '100%'
				rankElement.style.display = 'flex'
				rankElement.style.flexDirection = 'row'
				rankElement.style.justifyContent = 'center'

				let rankTag = document.createElement('p')
				rankTag.style.width = '30%'
				rankTag.style.margin = '0'
				if (i in marbleRaceConfig.theme.ranklistColor)
					rankTag.style.color = marbleRaceConfig.theme.ranklistColor[i]
				if (i in marbleRaceConfig.theme.ranklistText)
					rankTag.innerText = marbleRaceConfig.theme.ranklistText[i]
				else
					rankTag.innerText = marbleRaceConfig.text.rank.replace('%r', iStr)

				rankElement.appendChild(rankTag)
				this.rankTags[i - 1] = rankTag

				let rankTeamElement = document.createElement('p')
				rankTeamElement.style.width = '25%'
				rankTeamElement.style.margin = '0'
				rankTeamElement.innerText = ' '

				rankElement.appendChild(rankTeamElement)
				this.rankTeamElements[i - 1] = rankTeamElement

				let rankColorElement = document.createElement('p')
				rankColorElement.style.width = '25%'
				rankColorElement.style.margin = '0'
				rankColorElement.innerText = ' '

				rankElement.appendChild(rankColorElement)
				this.rankColorElements[i - 1] = rankColorElement

				let rankScoreElement = document.createElement('p')
				rankScoreElement.style.width = '20%'
				rankScoreElement.style.margin = '0'
				rankScoreElement.innerText = ' '

				rankElement.appendChild(rankScoreElement)
				this.rankScoreElements[i - 1] = rankScoreElement

				panel.appendChild(rankElement)
			}
		}

		this.interval = setInterval(function () {
			if (setting.calcTime) {
				let delta = marbleRaceConfig.renderTimeDelta * .001
				marbleRaceUIEngine.time += delta
				marbleRaceUIEngine.totalTime += delta
			}
			marbleRaceUIEngine.update()
		}, marbleRaceConfig.renderTimeDelta)
	},
	del: function () {
		clearInterval(this.interval)
	}
}

marbleRaceEngines.push({
	name: 'UI Engine v0.1',
	id: 'UIEngine01',
	engine: marbleRaceUIEngine
})